""" ****************************************************************
 Module: serialportmgr.py
 Ver 0.9.0

 Rev 0.9.2; Last: 03/11/2013 - Previous: 03/11/2013 (AEM)
   - Incorporate Plot DMM modules

 Rev 0.9.3-0; Last: 03/25/2013 - Previous: 03/24/2013 (AEM)
   - Mods to accommodate GUI (module readermain.py)
     Either execution mode is transparent to this module.

 Support functions for readmeter.py

 Set up serial port; get serial port readings.

 This file is part of the DMM Reader project.

 Copyright (C) 2012-2013  Arnold E. Morgan

    DMM Reader is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""

# *** System Supplied Modules ***
import serial
import time
import sys

# *** Custom Modules ***
import meterparse

def SetSerialPort(DevPort, BaudRate, TimeOut, NumBits):
   """ Set up and activate the serial port with parameters supplied
   from the config file.

   Return values back to the call as a 3 value tuple
      1 - RtnStat; False = Fail, True = Success
      2 - handle to open serial port
      3 - description of failure or empty string if port opened ok 
   """
   
   RtnValue = (False, '', '')    # *** Assume fail return state as default
   mymeter = None            # *** Handle to the serial port
   MeterMssg = ""            # *** Messaging passed back to the caller 

   # *** Set the device port, buad rate and timeout value
   try:
      mymeter = serial.Serial(DevPort, int(BaudRate), timeout=int(TimeOut))
      mymeter.bytesize = int(NumBits)
      mymeter.setRTS(0)
      mymeter.setDTR(1)
      #mymeter.open()   *** This is apparently not needed ***
      RtnValue = (True, mymeter, MeterMssg)
   except serial.SerialException, (strerror1):
      MeterMssg = "Open serial port attemp failed;\n(%s):" % (strerror1)
      RtnValue = (False, '', MeterMssg)
   except:
      MeterMssg =  "Open serial port attemp failed;\nunexpected error:\n(%s)" % (sys.exc_info()[0])
      RtnValue = (False, '', MeterMssg)
   # -------------------------------------------------------

   return RtnValue
# *************** End of fcn SetSerialPort ************

def ReadSerialPort(SerialDevice, CharsToRead):
   """ Trigger a reading, wait 1 sec for a response.

   Return the result to the caller as a string.
   """

   #DEBUG = True
   DEBUG = False
   RtnValue = (False, '')
   ReadResult = ""
   CharsAreWaiting = 0
   NumsToReturn = 0
   SerialDevice.write('\n')
   time.sleep(1)
   # *** .inWaiting() will return 14--usually (1st reading is 15?) ***
   CharsAreWaiting = SerialDevice.inWaiting()
   #print "Characters waiting to be read: %s" % SerialDevice.inWaiting()
   #print "Characters waiting to be read: %d" % CharsAreWaiting
   ReadResult = SerialDevice.read(int(CharsToRead))
   #print "\n     Raw ReadResult len: %d ***%s***\n" % (len(ReadResult), ReadResult)
   
   if DEBUG:
      Ctr = 0
      for x in ReadResult[:]:
         print x, Ctr, ord(x)
         Ctr += 1
    
   if CharsAreWaiting == 14 or CharsAreWaiting == 15:
      RtnValue = (True, ReadResult)
   
   return RtnValue
# *************** End of fcn ReadSerialPort ************

def GetMeterReading(SerialDevice, InputCharCnt):
   """ Get the reading from the serial port.

   Pass the reading to the functions in the meterparse
   module to extract the type and magnitude.
   
   Return values to the caller as a 4 value tuple
      1 - Meter reading value
      2 - Meter units label
      3 - StdOutStr, value to print to the terminal
      4 - LogOutStr, value to send to the log file
      5 - FailFlag, True = fail, False = success
      6 = MeterMssg, description if anything failed
   """
   
   RtnValue = ('', '', True, '')
   ReadStatus = ""
   meterresult = "" 
   MeterMssg = ""
   StdOutVal = ""
   LogOutVal = ""
   (ReadStatus, meterresult) = ReadSerialPort(SerialDevice, InputCharCnt)
   #print "RtnStat: %s; meterresult: %s" % (ReadStatus, meterresult)
            
   if not ReadStatus:
      MeterMssg = "Unable to read a valid value from the serial port"
      RtnValue = ('', '', '', '', True, MeterMssg)
   else:
      (ReadStatus, ValueMode, ValueSign, ValueMag, XMult) = meterparse.GetMeasType(meterresult)            
      #print "Stat: %s, Mode: %s, Sign: %s, Mag: %s, Mult: %s" % (RtnStat, ValueMode, ValueSign, ValueMag, XMult)

      if ReadStatus:
         if ValueMode == "TEMP":
            (MeterVal, MeterUnit, StdOutVal, LogOutVal) = meterparse.ConvertTempReading(ValueSign, ValueMag)
            RtnValue = (MeterVal, MeterUnit, StdOutVal, LogOutVal, False, '')
         elif ValueMode == "OHM":
            (MeterVal, MeterUnit, StdOutVal, LogOutVal) = meterparse.ConvertOhmReading(ValueMag, XMult)
            RtnValue = (MeterVal, MeterUnit, StdOutVal, LogOutVal, False, '')
         elif ValueMode == "DCV":
            (MeterVal, MeterUnit, StdOutVal, LogOutVal) = meterparse.ConvertDCVoltReading(ValueSign, ValueMag)
            RtnValue = (MeterVal, MeterUnit, StdOutVal, LogOutVal, False, '')
         elif ValueMode == "DCA":
            (MeterVal, MeterUnit, StdOutVal, LogOutVal) = meterparse.ConvertDCAmpReading(ValueSign, ValueMag, XMult)
            RtnValue = (MeterVal, MeterUnit, StdOutVal, LogOutVal, False, '')
         elif ValueMode == "ACA":
            (MeterVal, MeterUnit, StdOutVal, LogOutVal) = meterparse.ConvertACAmpReading(ValueSign, ValueMag, XMult)
            RtnValue = (MeterVal, MeterUnit, StdOutVal, LogOutVal, False, '')
         elif ValueMode == "ACV":
            (MeterVal, MeterUnit, StdOutVal, LogOutVal) = meterparse.ConvertACVoltReading(ValueMag)
            RtnValue = (MeterVal, MeterUnit, StdOutVal, LogOutVal, False, '')
      else:
         MeterMssg = "Unknown measurement type; terminating read loop"
         RtnValue = ('', '', '', '', True, MeterMssg)
      
   return RtnValue
# *************** End of fcn GetMeterReading ************
